package vg.modules.opener;


import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Observable;

import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JMenuItem;
import javax.swing.KeyStroke;
import javax.swing.filechooser.FileFilter;

import vg.services.data_base_manager.data.header.GraphModelHeader;
import vg.services.main_manager.MainManager;
import vg.services.plugin_manager.event_and_request.event.AUIEvent;
import vg.services.plugin_manager.event_and_request.event.UIEventOpenNewGraph;
import vg.services.plugin_manager.event_and_request.request.AUIRequest;
import vg.services.plugin_manager.event_and_request.request.UIRequestLoadProject;
import vg.services.plugin_manager.event_and_request.request.UIRequestSaveProject;
import vg.services.plugin_manager.interfaces.IPlugin;
import vg.services.plugin_manager.realization.PluginParameter;
import vg.services.user_interface_manager.interfaces.AMenuItem;

public class GUIOpener implements IPlugin {
	// Data
	private PluginParameter parameter;
	// Components
	private JMenuItem jMenuItem;
	private JFileChooser fileChooser;
	// Defines
	private final static String DEF_LAST_OPEN_GRAPH_DIR = "GRAPH_OPENER_LastDir";
	/**
	 * Installer.
	 */
	public void install(final PluginParameter param) {
		this.parameter = param;
		//---------------------------------------
		this.jMenuItem = new JMenuItem("Open file"); 
		this.jMenuItem.setIcon(new ImageIcon("./data/resources/textures/openFile.png"));
		//---------------------------------------
		this.jMenuItem.addActionListener(new ActionListener() {		
			public void actionPerformed(ActionEvent e) {
				openGraph();
			}
		});
		this.jMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_DOWN_MASK));
		//---------------------------------------
		this.parameter.userInterface.addMenuItem(new AMenuItem(this.jMenuItem) {
			public void update(Observable o, Object arg) {
				if(arg instanceof AUIEvent) {
					AUIEvent event = (AUIEvent)arg;
					switch (event.getType()) {
						case DEF_RESET: {
							// TODO
							break;
						}
						
						default: break;
					}
				} else if(arg instanceof AUIRequest){
					AUIRequest request = (AUIRequest)arg;
					switch(request.getType()) {
						case DEF_SAVE_PROJECT: {
							UIRequestSaveProject buf = (UIRequestSaveProject)request;
							saveProject(buf.getPath());
							break;
						}
						
						case DEF_LOAD_PROJECT: {
							final UIRequestLoadProject buf = (UIRequestLoadProject)request;
							MainManager.threadPool.submit(new Runnable() {
								public void run() {
									loadProject(buf.getPath());
								}
							});
							break;
						}
						
						default: break;
					}
				}
			}
		}, "File");
        fileChooser = new JFileChooser(".");
		String lastDir = MainManager.config.getProperty(GUIOpener.DEF_LAST_OPEN_GRAPH_DIR);
		if(lastDir != null) {
			fileChooser.setCurrentDirectory(new File(lastDir));
		}
        
        for (final String ext : CommandOpener.getAvailableExtensions()) {            	
        	fileChooser.addChoosableFileFilter(new FileFilter() {
				public String getDescription() {				
					return ext + " file (*." + ext +")";
				}
				public boolean accept(File f) {
					if (f != null) {
						if (f.isDirectory())
							return true;
						return f.getName().toLowerCase().endsWith(ext);
					}
					return false;
				}
			});
        }
	}
	private void openGraph() {		
		fileChooser.updateUI();
		if (fileChooser.showOpenDialog(parameter.userInterface.getMainFrame()) == JFileChooser.APPROVE_OPTION) {
			MainManager.log.printDebug("[" + this.getClass().getName() + ".openGraph] [PROCESS] Open file = " + fileChooser.getSelectedFile().getPath());
			MainManager.config.setProperty(GUIOpener.DEF_LAST_OPEN_GRAPH_DIR, fileChooser.getCurrentDirectory().getAbsolutePath());
			MainManager.threadPool.submit(new Runnable() {
				public void run() {
					try {
						String fileName = fileChooser.getSelectedFile().getPath();
						List<Integer> new_graph_id = CommandOpener.openFile(fileName, parameter.model);
						MainManager.log.printDebug("[" + this.getClass().getName() + ".openGraph] [OK] Open file = " + fileChooser.getSelectedFile().getPath());
						if(new_graph_id == null || new_graph_id.isEmpty()) {
							MainManager.windowMessage.errorMessage("Can't open file. May be file is empty", "Error");														
						} else {
							for(Integer buf : new_graph_id) {
								GraphModelHeader gh = parameter.model.getGraphModelHeader(buf);
								if(gh != null) {
									UIEventOpenNewGraph ong = new UIEventOpenNewGraph(buf, gh.name);
									parameter.userInterface.addEvent(ong);
								} else {
									MainManager.windowMessage.errorMessage("Can't open file. Database error", "Error");
								}							
							}
						}
					} catch (Throwable e) {
						MainManager.log.printException(e);
						MainManager.windowMessage.showExceptionMessage(new Exception("Can't open file.\nException : " + e.getMessage()));
					}
				}
			});
		}
	}
	/**
	 * This method saves all files, which contain 
	 * graphs and were used by user.
	 */
	private void saveProject(String path) {
		ArrayList<String> dontSavedFiles = new ArrayList<String>();	
		for (String fileName : CommandOpener.getOpenedFilesList()) {
			try {
				File oldFile = new File(fileName);
				File newFile = new File(path + File.separator + oldFile.getName());
				//we don't want have problems with coping file into itself
				if (oldFile.compareTo(newFile) == 0) {
					continue;
				}
				FileChannel originalGraphFile = new FileInputStream(oldFile).getChannel();
				FileChannel copyFile = new FileOutputStream(newFile).getChannel();
				try {
					originalGraphFile.transferTo(0, originalGraphFile.size(), copyFile);
				} catch (IOException e1) {
					throw e1;
				} finally {
					if (originalGraphFile != null) 
						originalGraphFile.close();
					if (copyFile != null)
						copyFile.close();
				}
			} catch (IOException e1) {
				MainManager.log.printException(e1);
				dontSavedFiles.add(fileName);
			}						
		}
		if (!dontSavedFiles.isEmpty()) {
			StringBuilder warningMessage = new StringBuilder("Could not save thoose files:");
			Iterator<String> doesntsaveFileIt = dontSavedFiles.iterator();
			while (doesntsaveFileIt.hasNext()) {
				warningMessage.append("\n");
				warningMessage.append(doesntsaveFileIt.next());								
			}
			
			MainManager.windowMessage.warningMessage(warningMessage.toString(), "Save project");
		}
	}
	/**
	 * This method loads all files, which contain 
	 * graphs and were used by user.
	 */
	private void loadProject(String path) {
		File dir = new File(path);
		if(dir.exists() && dir.isDirectory()) {		
			ArrayList<String> dontOpenedFiles = new ArrayList<String>();	
			for (String fileName : dir.list()) {
				String filePath = dir.getPath() + File.separator + fileName;
				for (final String ext : CommandOpener.getAvailableExtensions())
					if (filePath.toLowerCase().endsWith(ext)) {
						// TODO Need save to vgdb file and read from it.
/*						try {						
							int newGraphId = CommandOpener.openFile(filePath, this.parameter.model);
							GraphHeader gh = parameter.model.getGraphHeader(newGraphId);
							if(gh != null) {
								UIEventOpenNewGraph ong = new UIEventOpenNewGraph(newGraphId, gh.name);
								parameter.userInterface.addEvent(ong);
							} else {
								VisualGraph.windowMessage.errorMessage("Can't open file. Database error.", "Error");							
							}							
						} catch (CoreException e) {
							VisualGraph.log.printException(e);
							dontOpenedFiles.add(filePath);						
						}
*/					}
			}
			if (!dontOpenedFiles.isEmpty()) {
				StringBuilder warningMessage = new StringBuilder("Could not open file\n");
				for (String doesntOpenedFile : dontOpenedFiles) {
					warningMessage.append("\n");
					warningMessage.append(doesntOpenedFile);
				}
				MainManager.windowMessage.warningMessage(warningMessage.toString(), "Open project");
			}
		} else {
			MainManager.log.printError("[" + this.getClass().getName() + ".loadProject] is not directory (or not exist)");
		}
	}
}
